/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2019年8月22日
 * V4.0
 */
package com.jphenix.servlet.filter;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterConfig;

import com.jphenix.kernel.baseobject.instanceb.ABase;
import com.jphenix.servlet.common.HttpServletRequestImpl;
import com.jphenix.share.util.BaseUtil;
import com.jphenix.standard.docs.BeanInfo;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.docs.Register;
import com.jphenix.standard.docs.Running;
import com.jphenix.standard.servlet.IFilter;
import com.jphenix.standard.servlet.IRequest;
import com.jphenix.standard.servlet.IResponse;


/**
 * 虚拟动作上下文过滤器
 * com.jphenix.servlet.filter.VirtualContextFilter
 * 
 * 通常用在集群中的这种情况：当前服务器A，无虚拟路径。 
 * 有时候需要通过集群服务器B，代理访问服务器A。但服务器B
 * 是带虚拟路径的，代理访问服务器A获取的页面中，资源路径都不
 * 带服务器B的虚拟路径，导致页面中的资源无法再访问到服务器B，
 * 导致无法加载。
 * 
 * 虚拟路径过滤器的作用，在不修改Servlet容器配置（配置的无
 * 虚拟路径），在特定的虚拟路径请求进来时，会将这特定的虚拟路径
 * 转成真正的虚拟路径，虽然Servlet容器中没有配置这个虚拟路径。
 * 
 * 2019-08-24 优化了虚拟路径处理效率
 * 2019-08-26 去掉了setPathInfo设置值
 * 2019-08-31 完善了注释
 * 
 * @author MBG
 * 2019年8月22日
 */
@ClassInfo({"2019-08-31 14:38","虚拟动作上下文过滤器"})
@BeanInfo({"virtualcontextfilter"})
@Register({"filtervector"})
@Running({"99"})
public class VirtualContextFilter extends ABase implements IFilter {

	//虚拟上下文路径序列
	private List<String> vPath = new ArrayList<String>();
	
	/**
	 * 获取排序索引，数值越小越先执行
	 * 刘虻
	 * 2010-5-25 下午03:15:01
	 * @return 排序索引
	 */
	@Override
	public int getIndex() {
		return 1;
	}

	/**
	 * 获取需要过滤的动作路径扩展名
	 * 多个扩展名用逗号分割
	 * 多个扩展名用半角逗号分割
	 * 扩展名前不用加半角聚号（.)
	 * 如果返回空，或者空字符串，说明需要过滤全部动作路径（不建议这么做）
	 * 如果需要过滤无扩展名的动作，用半角减号（-）标记
	 * @return 需要过滤的动作路径扩展名
	 * 2014年9月12日
	 * @author 马宝刚
	 */
	@Override
	public String getFilterActionExtName() {
		return "*";
	}

	/**
	 * 执行过滤
	 * 刘虻
	 * 2010-5-25 下午04:09:25
	 * @param req 页面请求
	 * @param resp 页面反馈
	 * @return 如果返回真，则不继续往下进行，直接跳过结束
	 * @throws Exception 执行发生异常
	 */
	@Override
	public boolean doFilter(IRequest req, IResponse resp) throws Exception {
		String contextPath = req.getContextPath(); //当前虚拟路径
		String servletPath = req.getServletPath(); //当前动作路径
		//一级路径
		String[] pathInfos= getVirtualContextPath(servletPath);
		if(pathInfos==null || !vPath.contains(pathInfos[0])) {
			return false;
		}
		contextPath = contextPath+pathInfos[0]; //构造新的上下文路径
		((HttpServletRequestImpl)req).setContextPath(contextPath);  //设置新的上下文路径
		((HttpServletRequestImpl)req).setServletPath(pathInfos[1]); //设置减去一级路径的动作路径
		return false;
	}
	
	/**
	 * 从URL中获取一级子路径作为虚拟上下文
	 * @param servletPath 动作路径
	 * @return            0:一级子路径作为虚拟上下文 1:动作路径的后半部
	 * 2019年8月22日
	 * @author MBG
	 */
	private String[] getVirtualContextPath(String servletPath) {
		//分割位置
		int point = servletPath.indexOf("/",1);
		if(point<0) {
			return null;
		}
		return new String[] {
				 servletPath.substring(0,point)
				,servletPath.substring(point)};
	}
	
	/**
	 * 设置虚拟上下文路径
	 * @param virtualPath 虚拟上下文路径
	 * 2019年8月23日
	 * @author MBG
	 */
	public void setVirtualPath(String virtualPath) {
		if(virtualPath==null || virtualPath.length()<1) {
			return;
		}
		vPath.clear();
		List<String> paths = BaseUtil.splitToList(virtualPath,",");
		for(String ele:paths) {
			ele = ele.trim();
			if(!ele.startsWith("/")) {
				ele = "/"+ele;
			}
			if(vPath.contains(ele)) {
				continue;
			}
			vPath.add(ele);
		}
	}

	/**
	 * 执行初始化（无用）
	 * @param fe         过滤器管理类
	 * @param config     Servlet配置信息类
	 * @throws Exception 异常（如果初始化发生异常，则放弃不再使用）
	 * 2019年6月15日
	 * @author MBG
	 */
	@Override
	public void init(FilterExplorer fe, FilterConfig config) throws Exception {}

}
